package com.android.camera.ui;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.util.Log;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import android.widget.Scroller;
import android.os.Handler;
import android.os.Message;
import android.view.animation.DecelerateInterpolator;

import com.android.camera.CameraActivity;

import com.android.camera.R;
import com.android.camera.manager.RGK_BottomModePicker;

public class RgkBottomModeScrollLayout extends ViewGroup {
    private static final String TAG = "ScrollLayout";

    private boolean mCanMove = true;

    private Scroller mScroller;
    // private VelocityTracker mVelocityTracker;

    private static final int TOUCH_STATE_REST = 0;
    private static final int TOUCH_STATE_SCROLLING = 1;
    private static final int SNAP_VELOCITY = 600;
    private static final int DEFAULT_SCREEN = RGK_BottomModePicker.MODE_PHOTO_INDEX;
    private static final int SCROLL_DURATION = 360;

    private int mCurScreen;

    private int mTouchState = TOUCH_STATE_REST;

    private int mTouchSlop;

    private float mLastMotionX;
    private float mLastMotionY;

    private OnScrollToScreenListener mOnScrollToScreen = null;

    private boolean isScrolling = false;
    private boolean doAction = false;

    private static int SPACE_DISTANCE;

    private int chooseColor;
    private int noChooseColor;

    private static final int MSG_MODE_UPDATE = 1;
    private static final int MSG_MODE_SWITCH_FINISHED = 2;
    private boolean isTouching = false;

    private int[] scrollToXs = new int[RGK_BottomModePicker.MODE_COUNT];

    private int timeout = 0;

    private Context mContext;
    // private boolean isMeasured = false;

    private Handler mHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case MSG_MODE_UPDATE:
                    Log.d(TAG, "ScrollLayout->handleMessage(MSG_MODE_UPDATE): ");
                    // if (!isTouching) {
                    doScrollAction(mCurScreen);
                    // }
                    break;

                case MSG_MODE_SWITCH_FINISHED:
                    Log.d(TAG, "ScrollLayout->handleMessage(MSG_MODE_SWITCH_FINISHED): ");
                    doAction = false;
                    if (mOnScrollToScreen != null) {
                        mOnScrollToScreen.setIsModeSwitching(false);
                    }
                    break;
            }
        }

    };

    public boolean isScrolling() {
        return !mScroller.isFinished();
    }

    public RgkBottomModeScrollLayout(Context context) {
        this(context, null);
    }

    public RgkBottomModeScrollLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RgkBottomModeScrollLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mScroller = new Scroller(context, new DecelerateInterpolator());
        mCurScreen = DEFAULT_SCREEN;
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        chooseColor = context.getResources().getColor(R.color.mode_chose_color);
        noChooseColor = context.getResources().getColor(R.color.mode_not_chose_color);
        SPACE_DISTANCE = context.getResources().getDimensionPixelSize(R.dimen.modes_text_interval);
        mContext = context;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childLeft = 0;
        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View childView = getChildAt(i);
            if (childView.getVisibility() != View.GONE) {
                final int childWidth = childView.getMeasuredWidth();
                childView.layout(childLeft, 0, childLeft + childWidth,
                        childView.getMeasuredHeight());
                childLeft += childWidth + SPACE_DISTANCE;// 20 is gap space
            }
        }

        // bug-id:BWLLYBN-528 move code to onLayout for wrong ui show in clock
        // app
        initScrollToXs();
        scrollTo(scrollToXs[mCurScreen], 0);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        final int width = MeasureSpec.getSize(widthMeasureSpec);
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        if (widthMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException(
                    "ScrollLayout only canmCurScreen run at EXACTLY mode!");
        }

        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (heightMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException(
                    "ScrollLayout only can run at EXACTLY mode!");
        }

        // The children are given the same width and height as the scrollLayout
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            getChildAt(i).measure(
                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)/* widthMeasureSpec */,
                    heightMeasureSpec);
        }

        // scrollTo(getDefaultScrollOffset(mCurScreen), 0);
        // initScrollToXs();
        // scrollTo(scrollToXs[mCurScreen], 0);
        /*
         * if (!isMeasured) { isMeasured = true; doScrollAction(mCurScreen); }
         */
    }

    private void initScrollToXs() {
        int count = getChildCount();
        int[] childWidths = new int[count];
        for (int i = 0; i < count; i++) {
            childWidths[i] = getChildAt(i).getMeasuredWidth();
        }
        int halfParentWidth = getWidth() / 2;
        for (int i = 0; i < count; i++) {
            scrollToXs[i] = getScrollToX(childWidths, i, halfParentWidth);
        }
    }

    private int getScrollToX(int[] childWidths, int which, int halfParentWidth) {
        int offset = 0;
        for (int i = 0; i < which; i++) {
            offset += childWidths[i] + SPACE_DISTANCE;
        }
        return offset + childWidths[which] / 2 - halfParentWidth;
    }

    private int getDefaultScrollOffset(int which) {
        if (which >= getChildCount()) {
            return 0;
        }
        int offset = 0;
        for (int i = 0; i < which; i++) {
            offset += getChildAt(i).getMeasuredWidth();
        }
        offset += (which) * SPACE_DISTANCE + getChildAt(which).getMeasuredWidth() / 2;
        offset -= getWidth() / 2;
        return offset;
    }

    private int getFrontScrollOffset(int oldIndex, int delta) {
        int offset = getScrollX();
        int front = oldIndex + delta;
        int scroll = getChildAt(front).getMeasuredWidth() / 2 + SPACE_DISTANCE
                + getChildAt(oldIndex).getMeasuredWidth() / 2;
        for (int i = front + 1; i < oldIndex; i++) {
            scroll += getChildAt(i).getMeasuredWidth() + SPACE_DISTANCE;
        }
        return offset - scroll;
    }

    private int getNextScrollOffset(int oldIndex, int delta) {
        int offset = getScrollX();
        int next = oldIndex + delta;
        int scroll = getChildAt(oldIndex).getMeasuredWidth() / 2 + SPACE_DISTANCE
                + getChildAt(next).getMeasuredWidth() / 2;
        for (int i = oldIndex + 1; i < next; i++) {
            scroll += getChildAt(i).getMeasuredWidth() + SPACE_DISTANCE;
        }
        return offset + scroll;
    }

    public void setTouchMove(boolean canMove) {
        this.mCanMove = canMove;
    }

    public void snapToScreen(int whichScreen) {

        if (mOnScrollToScreen != null) {
            mOnScrollToScreen.setIsModeSwitching(true);
        }
        // bug-id:DWYQYSB-394 disable shutter manager during scroll bottom
        if (((CameraActivity) mContext).getShutterManager().isEnabled()) {
            ((CameraActivity) mContext).getShutterManager().setEnabled(false);
        }

        if (!mScroller.isFinished()) {
            mScroller.abortAnimation();
        }

        int curScrollX = getScrollX();
        int dest = scrollToXs[whichScreen];

        Log.d(TAG, "ScrollLayout->[snapToScreen] dest=" + dest + ", curScrollX=" + curScrollX);

        mCurScreen = whichScreen;
        if (curScrollX != dest) {
            final int delta = dest - curScrollX;
            timeout = Math.abs(delta) * 2;
            Log.d(TAG, "ScrollLayout->[snapToScreen]---------------- timeout=" + timeout);
            mScroller.startScroll(curScrollX, 0, delta, 0, SCROLL_DURATION);//timeout);
            updateTextColor(mCurScreen);
            invalidate();
        }
    }

    public void setToScreen(int whichScreen) {
        Log.d(TAG, "ScrollLayout->[setToScreen] whichScreen=" + whichScreen);
        if (whichScreen == mCurScreen) {
            Log.d(TAG, "ScrollLayout->[setToScreen] screen no change");
            return;
        }
        if (doAction) {
            Log.d(TAG, "ScrollLayout->[setToScreen] doAction == true");
            return;
        }

        // M bug-id:DWYQYSB-305 disable shuttermanager during switching mode
        // start
        if (((CameraActivity) mContext).getShutterManager().isEnabled()) {
            ((CameraActivity) mContext).getShutterManager().setEnabled(false);
        }
        mHandler.removeMessages(MSG_MODE_UPDATE);
        snapToScreen(whichScreen);
        mHandler.sendEmptyMessageDelayed(MSG_MODE_UPDATE, 0);
        // M bug-id:DWYQYSB-305 disable shuttermanager during switching mode end
    }

    public int getCurScreen() {
        return mCurScreen;
    }

    public void autoRecovery() {
        mScroller.abortAnimation();
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            postInvalidate();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // M bug-id:DWYQYSB-161 add videorecording state judage for botoom
        // scroll event
        if (!mCanMove || !((CameraActivity) mContext).canModeBeSwitched()) {
            Log.d(TAG, "ScrollLayout->[onTouchEvent] can't move, return.");
            return true;
        }

        final int action = event.getAction();
        final float x = event.getX();
        // final float y = event.getY();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                if (doAction) {
                    Log.d(TAG, "ScrollLayout->[onTouchEvent] action_down: when doing action.");
                    return false;
                }

                isTouching = true;
                mLastMotionX = x;
                Log.d(TAG,
                        "ScrollLayout->[onTouchEvent] action_down:---------------------x=" + x);
                break;
            case MotionEvent.ACTION_MOVE:
                if (isScrolling) {
                    Log.d(TAG,
                            "ScrollLayout->[onTouchEvent] action_move: when child is scrolling.");
                    return true;
                }
                int deltaX = (int) (x - mLastMotionX);
                int childCount = getChildCount();

                if (doAction) {
                    Log.d(TAG, "ScrollLayout->[onTouchEvent] action_down: when doing action.");
                    return false;
                }

                Log.d(TAG,
                        "ScrollLayout->[onTouchEvent] action_move:---------------------mCurScreen="
                                + mCurScreen);
                if (deltaX > 50 /* && mCurScreen > 0 */) {
                    Log.d(TAG,
                            "ScrollLayout->[onTouchEvent] action_move:----------------move left.");
                    mHandler.removeMessages(MSG_MODE_UPDATE);
                    isScrolling = true;
                    if (mCurScreen > 0) {
                        snapToScreen(mCurScreen - 1);
                    }
                } else if (deltaX < -50 /* && mCurScreen < childCount - 1 */) {
                    Log.d(TAG,
                            "ScrollLayout->[onTouchEvent] action_move:----------------move right.");
                    mHandler.removeMessages(MSG_MODE_UPDATE);
                    isScrolling = true;
                    if (mCurScreen < childCount - 1) {
                        snapToScreen(mCurScreen + 1);
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                isTouching = false;
                if (isScrolling) {
                    Log.d(TAG,
                            "ScrollLayout->[onTouchEvent] action_up: when child is scrolling.");

                    mTouchState = TOUCH_STATE_REST;
                    isScrolling = false;
                    if (mScroller.isFinished()) {
                        mHandler.sendEmptyMessage(MSG_MODE_UPDATE);
                    } else {
                        mHandler.sendEmptyMessageDelayed(MSG_MODE_UPDATE, timeout);
                    }
                    return true;
                }

                mTouchState = TOUCH_STATE_REST;
                break;
            case MotionEvent.ACTION_CANCEL:
                if (mOnScrollToScreen != null) {
                    mOnScrollToScreen.setIsModeSwitching(false);
                }
                mTouchState = TOUCH_STATE_REST;
                break;
            default:
                break;
        }
        return true;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
        if ((action == MotionEvent.ACTION_MOVE)
                && (mTouchState != TOUCH_STATE_REST)) {
            return true;
        }
        final float x = ev.getX();
        final float y = ev.getY();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mLastMotionX = x;
                mLastMotionY = y;
                mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST
                        : TOUCH_STATE_SCROLLING;
                break;
            case MotionEvent.ACTION_MOVE:
                final int xDiff = (int) Math.abs(mLastMotionX - x);
                if (xDiff > mTouchSlop) {
                    if (Math.abs(mLastMotionY - y) / Math.abs(mLastMotionX - x) < 1) {
                        mTouchState = TOUCH_STATE_SCROLLING;
                    }
                }
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                mTouchState = TOUCH_STATE_REST;
                break;
            default:
                break;
        }
        return mTouchState != TOUCH_STATE_REST;
    }

    private void updateTextColor(int currentScreen) {
        int count = getChildCount();
        for (int i = 0; i < count; i++) {
            // if (getChildAt(whichScreen) instanceof TextView) {
            if (i == currentScreen) {
                TextView txt = (TextView) getChildAt(i);
                txt.setTextColor(chooseColor);
            } else {
                TextView txt = (TextView) getChildAt(i);
                txt.setTextColor(noChooseColor);
            }
            // }
        }
    }

    private void doScrollAction(int whichScreen) {
        if (mOnScrollToScreen != null) {
            doAction = true;
            mOnScrollToScreen.doAction(whichScreen);
        }
    }

    public void onModeChangeSuccess() {
        mHandler.sendEmptyMessageDelayed(MSG_MODE_SWITCH_FINISHED, 50);
        // doAction = false;
    }

    public void setOnScrollToScreen(
            OnScrollToScreenListener paramOnScrollToScreen) {
        mOnScrollToScreen = paramOnScrollToScreen;
    }

    public void setDefaultScreen(int position) {
        mCurScreen = position;
    }

    public interface OnScrollToScreenListener {
        public void doAction(int whichScreen);
        public void setIsModeSwitching(boolean switching);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
    }

    public void release() {
        isScrolling = false;
        doAction = false;
        isTouching = false;
        mCurScreen = DEFAULT_SCREEN;
    }

    public void restore(int whichScreen) {
        snapToScreen(whichScreen);
        if (mOnScrollToScreen != null) {
            mOnScrollToScreen.setIsModeSwitching(false);
        }
        if (!((CameraActivity) mContext).getShutterManager().isEnabled()) {
            ((CameraActivity) mContext).getShutterManager().setEnabled(true);
        }
        updateTextColor(whichScreen);
    }
}
